package boids.preys;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import boids.Boid;
import boids.predators.Predator;

import util.Vector;

public abstract class AbstractPrey implements Prey, Boid
{
	protected Vector location, velocity;
	protected Vector oldLocation, oldVelocity;
	protected boolean alarmed;
	protected double envWidth, envHeight;
	
	protected static double SIZE = 1;
	protected static double PERCEPTION_RADIUS = 50;
	protected static double SEPARATION_RADIUS = PERCEPTION_RADIUS / 4;
	protected static double ESCAPE_RADIUS = PERCEPTION_RADIUS;
	protected static double MAX_SPEED = 5;
	protected static double MAX_FORCE = 0.5 * MAX_SPEED;
	protected  double MIN_FORCE;// = 0.2 * MAX_FORCE;
	
	protected static int ID_COUNTER = 0;
	protected int id;
	
	public AbstractPrey(Vector location, Vector velocity, double envWidth, double envHeight)
	{
		this.location = location;
		oldLocation = this.location.clone();
		
		this.velocity = velocity;
		oldVelocity = this.velocity.clone();
		
		alarmed = false;
		MIN_FORCE = 0.2 * MAX_FORCE;
		
		this.envWidth = envWidth;
		this.envHeight = envHeight;
		
		id = ID_COUNTER++;
	}
	
	public void cleanUpdate()
	{
		oldVelocity = velocity.clone();
		oldLocation = location.clone();
	}
	
	protected ArrayList<Prey> findNeighbors(ArrayList<Prey> preys)
	{
		ArrayList<Prey> neighbors = new ArrayList<Prey>();
		
		for (Prey b : preys)
		{
			double distance = location.euclDistance(b.getLocation());
			
			if (distance <= PERCEPTION_RADIUS && (id != b.getID()))
			{
				neighbors.add(b);
			}
		}
		
		return neighbors;
	}
	
	protected ArrayList<Predator> findPredators(ArrayList<Predator> predators)
	{
		ArrayList<Predator> predatorsInRange = new ArrayList<Predator>();
		
		for (Predator p : predators)
		{
			double distance = location.euclDistance(p.getLocation());
			
			if (distance < PERCEPTION_RADIUS)
			{
				predatorsInRange.add(p);
			}
		}
		
		alarmed = (predatorsInRange.size() > 0);
		
		return predatorsInRange;
	}
	
	protected Vector steerTo(Vector target)
	{
		Vector desired = Vector.substract(target, location);
		double d = desired.magnitude();
		
		if (d > 0)
		{
			desired.normalize();
			
			if (d < 100)
			{
				desired.multiply(MAX_SPEED * (d/100.0));
			}
			else
			{
				desired.multiply(MAX_SPEED);
			}
			
			Vector steer = Vector.substract(desired, velocity);
			steer.limit(MAX_FORCE);
			
			return steer;
		}
		
		return new Vector();
	}
	
	public boolean isAlarmed()
	{
		return alarmed;
	}
	
	public Vector getLocation()
	{
		return oldLocation.clone();
	}
	
	public void setLocation(Vector location)
	{
		this.location = location;
	}
	
	public Vector getVelocity()
	{
		return oldVelocity.clone();
	}
	
	public int getID()
	{
		return id;
	}
	
	public void draw(Graphics2D g2)
	{
		Rectangle2D.Double body = new Rectangle2D.Double(location.getX() - SIZE/2,
								location.getY() - SIZE/2,
								SIZE,
								SIZE);
		if (alarmed) g2.setColor(Color.RED);
		else g2.setColor(Color.BLACK);
		g2.fill(body);
		g2.draw(body);
	}

}
